package vivace.helper;

import java.awt.*;
import javax.swing.JPanel;
import vivace.model.*;
import vivace.helper.*;

public class GridHelper {

	/**
	 * The different kinds of grid
	 */
	public enum Type{OVERVIEW,PIANOROLL};

	private Project project;
	private int height;
	private Type type;
	private boolean snap;

	/**
	 * Returns the total width of the grid
	 */
	public int getWidth(){
		return tickToXPosition( project.getSequenceLength() );
	}

	/**
	 * Returns the total height of the grid
	 */
	public int getHeight(){
		return height;
	}

	/**
	 * Returns whether snap to grid is enabled or not
	 */
	public boolean getSnap(){
		return snap;
	}

	/**
	 * Sets whether snap to grid is enabled or not 
	 */
	public void setSnap( boolean b ){
		this.snap = b;
	}
	
	/**
	 * Constructor
	 * @param project
	 * @param type
	 */
	public GridHelper( Project project, Type type ){
		
		this.project = project;
		this.type = type;
		this.snap = false;
		
		// The height is static, so we can define it here
		if( type.equals( Type.OVERVIEW ) ){
			this.height = (project.getTracks().length - 1) * GUIHelper.TRACK_HEIGHT;
		} else {
			this.height = 128 * GUIHelper.NOTE_HEIGHT;
		}
		
		
	}
	
	
	/** 
	 * Returns the x-position of a tick
	 */
	public int tickToXPosition( long tick ){
		double m = (project.getPPQ() * 4);
		int n = (project.getZoomLevel());
		return (int) Math.ceil((tick/m) * n);
	}
	
	/**
	 * Returns a tick from a x-position. If snap is set to true the return
	 * value is rounded to match the closest quarter note.
	 */
	public int xPositionToTick( int xPos ){
		int m = (project.getPPQ() * 4);
		int n = (project.getZoomLevel());
		int tick = (int) Math.ceil((xPos/n)*m);
		if( snap )
			return Math.round(tick/project.getPPQ()) * tick;
		else
			return tick;
	}
	
	/**
	 * Returns the y-position of a note
	 */
	public int noteToYPosition( int note ){
		return GUIHelper.NOTE_HEIGHT * Math.abs(note - 127);
	}
	
	/**
	 * Returns a note value from an y-position.
	 */
	public int yPositionToNote( int yPos ){
		return 0;
	}
	
	
	/** Paints the grid	 */
	public void paintGrid( Graphics g ){
	
		// Draw the vertical lines
		
		//The height of the grid
		int lengthOfLineX = this.height;

		//Get a 2D list with information about the time signatures
		int timeSignature[][] = project.getTimeSignatures();

		//Number of ticks of a 4/4
		int ticksPerQuarter = project.getPPQ() * 4;

		//How long is a 4/4 in pixels
		int lengthQuartInPixel = project.getZoomLevel();

		//This counter keep track of the number of ticks into the midi-file we are
		int ticksCounter = 0;

		//Keeps track of what event (timesignature) we are calculating on
		int currEvent = 0;

		//The pixels where the big line will be painted
		int pixelBig = 0;

		//The pixels where the small line will be painted
		int pixelSmall = 0;

		//The difference in pixel between small lines in current time signature
		int pixelSmallSpace = 0;

		//what time signature are we at
		int countNumber = 0;

		//Paint as long as the song contains information
		while(ticksCounter <= project.getSequenceLength()){

			//The Color of the BIG Lines
			g.setColor(Color.GRAY);
			
			//The fat line at the start of each time signature
			g.fillRect(pixelBig, 0, 1, lengthOfLineX);

			//The small lines are pianted after a big one, so set the small lines to begin at the current big line x-marker
			pixelSmall = pixelBig;

			//Calculate where next BIG marker will be;
			pixelBig = pixelBig + (lengthQuartInPixel*timeSignature[currEvent][0])/timeSignature[currEvent][1];

			//The Color of the Small Lines
			g.setColor(Color.LIGHT_GRAY);
			
			//Paint the small lines between the big ones
			for(int z = 0; z < (timeSignature[currEvent][0]-1); z++) {

				//Calculate where the small lines will be put
				//If this is the first line after a BIG line
				if(z == 0){

					//Then set up the space between each small line in a time signature
					pixelSmallSpace = (pixelBig-pixelSmall)/timeSignature[currEvent][0];

					//Then make the first tick draw one space after the 
					pixelSmall = pixelSmall + pixelSmallSpace;
					
				} else {

					//Otherwise step a small space more
					pixelSmall = pixelSmall + pixelSmallSpace;
				}

				//Draw the small line at the ticksSmall pixel value
				g.drawLine((int)pixelSmall, 0, (int)pixelSmall, lengthOfLineX);

			}

			int ticksPerCurrQuarter = 0;
			//If the next timeSignature is the current tickCounter and the upcoming timeSignature is not the first one ...
			if(timeSignature[currEvent+1][2] == ticksCounter && (timeSignature[currEvent+1][2] != 0)){

				//Increase the value of the currentEvent, this will make the program draw a new time signature
				currEvent++;

				//If this is the first timeSignature in the midi-file ...
				if(countNumber == 0 ){

					//We will have to get the information from the current event not the new
					//Set the number of ticks between the current time signature
					ticksPerCurrQuarter = (ticksPerQuarter*timeSignature[currEvent-1][0])/timeSignature[currEvent-1][1];

				} else {

					//else we set the number of ticks between the current time signature to the upcoming time signature
					ticksPerCurrQuarter = (ticksPerQuarter*timeSignature[currEvent][0])/timeSignature[currEvent][1];
				}

			//If the track only contains one timesignature we dont want to update to a new one
			} else {
				ticksPerCurrQuarter = (ticksPerQuarter*timeSignature[currEvent][0])/timeSignature[currEvent][1];
			}

			//The ticksCounter is the old ticks + the new number of ticks between the current time signature
			ticksCounter = ticksCounter + ticksPerCurrQuarter;

			//Increase timesignature counter
			countNumber++;
		}

		//Paint the final big line and text
		g.fillRect(pixelBig, 0, 1, 7);
		
		
		// Draw the horisontal lines 
		if( type.equals(Type.PIANOROLL)){
			
			g.setColor(Color.BLACK);
			int curY = 0;
			int wid = this.getWidth();
			for( int i = 0; i < 128; i++){
				g.drawLine(0,curY,wid,curY);
				curY += GUIHelper.NOTE_HEIGHT;
			}
			
		} else {
			
			g.setColor(Color.BLACK);
			int curY = 0;
			int wid = this.getWidth();
			for( int i = 0; i < this.project.getSequencer().getSequence().getTracks().length; i++){
				g.drawLine(0,curY,wid,curY);
				curY += GUIHelper.TRACK_HEIGHT;
			}
			
		}
	
	}
	

}
